package com.aceitunaproject.server.installation;

import java.awt.Point;
import java.util.List;
import java.util.logging.Logger;

import com.aceitunaproject.server.AceitunaContext;
import com.aceitunaproject.server.counter.Counter;
import com.aceitunaproject.server.entity.installation.Installation;
import com.aceitunaproject.server.entity.unit.Unit;
import com.aceitunaproject.server.map.MapManager;
import com.aceitunaproject.server.map.MapTile;
import com.aceitunaproject.server.materialgoods.MaterialGood;
import com.aceitunaproject.server.player.Player;
import com.aceitunaproject.server.terrain.TerrainType;
import com.aceitunaproject.shared.exceptions.gamerules.EnumIllegalAction;
import com.aceitunaproject.shared.exceptions.gamerules.IllegalActionException;
import com.sun.sgs.app.AppContext;

/**
 * Settlement Manager interface implementation
 * 
 * @author Federico Bergstein
 * 
 * 
 */
public class InstallationManagerImpl implements InstallationManager {

	private static final String INSTALLATION_PREFIX = "INSTALLATION";
	private static final String COUNTERNAME = "InstallationCounter";

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.aceitunaproject.server.settlement.SettlementManager#buildSettlement
	 * (java.lang.String, int, int, int,
	 * com.aceitunaproject.server.player.Player,
	 * com.aceitunaproject.server.player.Player, double,
	 * com.aceitunaproject.server.entity.EntityRelationships)
	 */
	private Installation createInstallation(String name, Player player,
			InstallationType type, Point position, Unit unit) {

		Installation newInstallation = new Installation(getNewCount(), name,
				player, player, position, unit, false, type, 0);

		AppContext.getDataManager().setBinding(
				INSTALLATION_PREFIX + newInstallation.getId(), newInstallation);
		unit.setInstallationBeingBuilt(newInstallation.getId());
		Logger.getLogger(this.getClass().getName()).info(
				"building installation " + name + " in " + position.x + " , "
						+ position.y);

		return newInstallation;
	}

	private static Long getNewCount() {
		if (!Counter.counterExists(COUNTERNAME)) {
			Counter.createCounter(COUNTERNAME);
		}
		return Counter.getNewCount(COUNTERNAME);
	}

	@Override
	public Installation buildInstallation(InstallationType type, String name,
			int positionX, int positionY, Unit unit,
			List<GoodSource> goodSources) throws IllegalActionException {

		MapManager mapManager = AceitunaContext.getMapManager();
		MapTile tile = mapManager.getTile(positionX, positionY);

		if (tile.getInstallations().size() >= mapManager
				.getInstallationLimit(tile)) {
			throw new IllegalActionException(
					EnumIllegalAction.BUILD_INSTALLATION_TILE_INSTALLATION_LIMIT_REACHED);
		}
		if (!unit.getController().getScientificAdvances().containsAll(
				type.getRequiredScientificAdvances())) {
			throw new IllegalActionException(
					EnumIllegalAction.BUILD_INSTALLATION_UNIT_CONTROLLER_LACKS_REQUIRED_SCIENTIFIC_ADVANCE);
		}

		if (!unit.getEquipment().values().containsAll(
				type.getBuildingRequiredEquipment())) {
			throw new IllegalActionException(
					EnumIllegalAction.BUILD_INSTALLATION_UNIT_UNABLE_TO_BUILD_INSTALLATION_TYPE);
		}

		if (!unit.getCurrentPosition().equals(new Point(positionX, positionY))) {
			if (!mapManager.getAdjacentTiles(tile).contains(
					mapManager.getTile(unit.getCurrentPosition()))) {
				throw new IllegalActionException(
						EnumIllegalAction.BUILD_INSTALLATION_MUST_BE_BUILT_IN_UNITS_CURRENT_POSITION_OR_ADJACENT_TILE);
			}
		}

		boolean allowed = false;
		for (TerrainType terrain : tile.getTerrainTypes().values()) {

			if (terrain.getDisAllowedInstallationTypes().contains(type)) {
				throw new IllegalActionException(
						EnumIllegalAction.BUILD_INSTALLATION_CANNOT_BE_BUILT_IN_TILE_TERRAIN);
			}
			if (terrain.getAllowedInstallationTypes().contains(type)) {
				allowed = true;
			}

		}
		if (!allowed) {
			throw new IllegalActionException(
					EnumIllegalAction.BUILD_INSTALLATION_CANNOT_BE_BUILT_IN_TILE_TERRAIN);
		}

		hasNecesaryMaterials(type, goodSources);

		for (GoodSource goodSource : goodSources) {

			goodSource.getContainer().retireCargo(unit.getController(),
					goodSource.getGood(), goodSource.getBlocks());
		}

		Installation newInstallation = createInstallation(name, unit
				.getController(), type, new Point(positionX, positionY), unit);

		Logger.getLogger(this.getClass().getName()).info(
				"placing installation " + name + " in " + positionX + " , "
						+ positionY);

		tile.addInstallation(newInstallation);

		return newInstallation;

	}

	@Override
	public Installation getInstallation(Long id) {
		return (Installation) AppContext.getDataManager().getBinding(
				INSTALLATION_PREFIX + id);

	}

	@Override
	public void buildInstallation(String name, String installationType,
			Unit unit, int x, int y, List<GoodSource> goodSources)
			throws IllegalActionException {

		InstallationType type = AceitunaContext.getInstallationTypeManager()
				.getAllInstallationTypes().get(installationType);
		if (type == null) {
			throw new IllegalActionException(
					EnumIllegalAction.BUILD_INSTALLATION_INSTALLATION_TYPE_NOT_FOUND);
		} else {
			buildInstallation(type, name, x, y, unit, goodSources);
		}

	}

	private void hasNecesaryMaterials(InstallationType type,
			List<GoodSource> goodSources) throws IllegalActionException {
		for (MaterialGood good : type.getBuildingRequiredGoods().keySet()) {

			Long blocksRequired = type.getBuildingRequiredGoods().get(good);
			Long blocksSupplied = Long.valueOf(0);
			for (GoodSource goodSource : goodSources) {
				if (goodSource.getGood().equals(good)) {
					blocksSupplied += goodSource.getBlocks();
				}
			}
			if (blocksSupplied < blocksRequired) {
				throw new IllegalActionException(
						EnumIllegalAction.BUILD_INSTALLATION_INSUFICIENT_MATERIALS);
			}
		}

	}
}
